Passed
Push — master ( a5f6f2...cdb66d )
by Tony
01:49
created

$.extend.always   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 0
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
(function (jQuery) {
2
'use strict';
3
4
jQuery = jQuery && jQuery.hasOwnProperty('default') ? jQuery['default'] : jQuery;
5
6
var AlwaysData = (function () {
7
    function AlwaysData() {
8
    }
9
    AlwaysData.OPERATION_INSERTION = 0;
10
    AlwaysData.OPERATION_REMOVAL = 1;
11
    return AlwaysData;
12
}());
13
14
var Always = (function () {
15
    function Always(element) {
16
        var _this = this;
17
        this.insertedCallbacks = {};
18
        this.removedCallbacks = {};
19
        this.element = element;
20
        this.observer = new MutationObserver(function (mutations) { return mutations.forEach(function (mutation) {
0 ignored issues
show
Bug introduced by
The variable MutationObserver seems to be never declared. If this is a global, consider adding a /** global: MutationObserver */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
21
            if ('childList' !== mutation.type) {
22
                return;
23
            }
24
            [].forEach.call(mutation.addedNodes, function (node) {
25
                if (!(node instanceof HTMLElement)) {
0 ignored issues
show
Bug introduced by
The variable HTMLElement seems to be never declared. If this is a global, consider adding a /** global: HTMLElement */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
26
                    return;
27
                }
28
                _this.notifyInserted(node);
29
            });
30
            [].forEach.call(mutation.removedNodes, function (node) {
31
                if (!(node instanceof HTMLElement)) {
0 ignored issues
show
Bug introduced by
The variable HTMLElement seems to be never declared. If this is a global, consider adding a /** global: HTMLElement */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
32
                    return;
33
                }
34
                _this.notifyRemoved(node);
35
            });
36
        }); });
37
        this.observer.observe(this.element, {
38
            childList: true,
39
            subtree: true
40
        });
41
    }
42
    Always.data = function (element) {
43
        if (!element.hasOwnProperty('jQueryAlways')) {
44
            Object.defineProperty(element, 'jQueryAlways', {
45
                value: new AlwaysData(),
46
                configurable: true
47
            });
48
        }
49
        return element.jQueryAlways;
50
    };
51
    Always.attach = function (element) {
52
        var data = this.data(element);
53
        if (!data.instance) {
54
            data.instance = new Always(element);
55
        }
56
        return data.instance;
57
    };
58
    Always.detach = function (element) {
59
        Always.attach(element).observer.disconnect();
60
        delete element.jQueryAlways;
61
    };
62
    Always.normalizeSelector = function (selector) {
63
        return selector.split(',').map(function (part) {
64
            return part.trim();
65
        }).sort().join(',');
66
    };
67
    Always.always = function (element, selector, onInserted, onRemoved) {
68
        var instance = Always.attach(element);
69
        if ('function' === typeof onInserted) {
70
            instance.addInsertedCallback(selector, onInserted);
71
            [].forEach.call(element.querySelectorAll(selector), function (node) {
72
                onInserted.call(node);
73
            });
74
        }
75
        if ('function' === typeof onRemoved) {
76
            instance.addRemovedCallback(selector, onRemoved);
77
        }
78
    };
79
    Always.never = function (element, selector, onInserted, onRemoved) {
80
        if (!selector) {
81
            Always.detach(element);
82
            return;
83
        }
84
        var instance = Always.attach(element);
85
        if (!onInserted && !onRemoved) {
86
            instance.removeInsertedCallback(selector);
87
            instance.removeRemovedCallback(selector);
88
            return;
89
        }
90
        if (onInserted) {
91
            instance.removeInsertedCallback(selector, onInserted);
92
        }
93
        if (onRemoved) {
94
            instance.removeRemovedCallback(selector, onRemoved);
95
        }
96
    };
97
    Always.prototype.addCallback = function (callbacks, selector, callback) {
98
        selector = Always.normalizeSelector(selector);
99
        if (!callbacks.hasOwnProperty(selector)) {
100
            callbacks[selector] = [];
101
        }
102
        callbacks[selector].push(callback);
103
        return this;
104
    };
105
    Always.prototype.removeCallback = function (callbacks, selector, callback) {
106
        selector = Always.normalizeSelector(selector);
107
        if (!callbacks.hasOwnProperty(selector)) {
108
            return this;
109
        }
110
        if (callback) {
111
            var index = void 0;
0 ignored issues
show
Unused Code introduced by
The assignment to variable index seems to be never used. Consider removing it.
Loading history...
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
112
            while (-1 < (index = callbacks[selector].indexOf(callback))) {
113
                callbacks[selector].splice(index, 1);
114
            }
115
        }
116
        else {
117
            delete callbacks[selector];
118
        }
119
        return this;
120
    };
121
    Always.prototype.notifyInserted = function (element) {
122
        var _this = this;
123
        var data = Always.data(element);
124
        if (AlwaysData.OPERATION_INSERTION === data.lastOperation) {
125
            return this;
126
        }
127
        data.lastOperation = AlwaysData.OPERATION_INSERTION;
128
        Object.keys(this.insertedCallbacks).forEach(function (selector) {
129
            if (element.matches(selector)) {
130
                _this.insertedCallbacks[selector].forEach(function (callback) {
131
                    callback.call(element);
132
                });
133
            }
134
        });
135
        [].forEach.call(element.querySelectorAll('*'), function (node) {
136
            _this.notifyInserted(node);
137
        });
138
        return this;
139
    };
140
    Always.prototype.notifyRemoved = function (element) {
141
        var _this = this;
142
        var data = Always.data(element);
143
        if (AlwaysData.OPERATION_REMOVAL === data.lastOperation) {
144
            return this;
145
        }
146
        data.lastOperation = AlwaysData.OPERATION_REMOVAL;
147
        [].forEach.call(element.querySelectorAll('*'), function (node) {
148
            _this.notifyRemoved(node);
149
        });
150
        Object.keys(this.removedCallbacks).forEach(function (selector) {
151
            if (element.matches(selector)) {
152
                _this.removedCallbacks[selector].forEach(function (callback) {
153
                    callback.call(element);
154
                });
155
            }
156
        });
157
        return this;
158
    };
159
    Always.prototype.addInsertedCallback = function (selector, callback) {
160
        return this.addCallback(this.insertedCallbacks, selector, callback);
161
    };
162
    Always.prototype.addRemovedCallback = function (selector, callback) {
163
        return this.addCallback(this.removedCallbacks, selector, callback);
164
    };
165
    Always.prototype.removeInsertedCallback = function (selector, callback) {
166
        return this.removeCallback(this.insertedCallbacks, selector, callback);
167
    };
168
    Always.prototype.removeRemovedCallback = function (selector, callback) {
169
        return this.removeCallback(this.removedCallbacks, selector, callback);
170
    };
171
    return Always;
172
}());
173
174
function bindingNative() {
175
    window.Always = {
176
        always: Always.always,
177
        never: Always.never
178
    };
179
}
180
181
function bindingJQuery() {
182
    if ('undefined' === typeof jQuery) {
183
        return;
184
    }
185
    (function ($) {
186
        $.extend($.fn, {
187
            always: function (selector, onInserted, onRemoved) {
188
                return $(this).each(function () {
189
                    Always.always(this, selector, onInserted, onRemoved);
190
                });
191
            },
192
            never: function (selector, onInserted, onRemoved) {
193
                return $(this).each(function () {
194
                    Always.never(this, selector, onInserted, onRemoved);
195
                });
196
            }
197
        });
198
    })(jQuery);
199
}
200
201
var Bindings = (function () {
202
    function Bindings() {
203
    }
204
    Bindings.native = bindingNative;
205
    Bindings.jQuery = bindingJQuery;
206
    return Bindings;
207
}());
208
209
function polyfillMutationObserver() {
210
    if (window.MutationObserver) {
211
        return;
212
    }
213
    window.MutationObserver = window.WebKitMutationObserver;
214
}
215
216
function polyfillElementMatches() {
217
    var _this = this;
218
    var prototype = Element.prototype;
0 ignored issues
show
Bug introduced by
The variable Element seems to be never declared. If this is a global, consider adding a /** global: Element */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
219
    if (prototype.matches) {
220
        return;
221
    }
222
    prototype.matches =
223
        prototype.matchesSelector ||
224
            prototype.mozMatchesSelector ||
225
            prototype.msMatchesSelector ||
226
            prototype.oMatchesSelector ||
227
            prototype.webkitMatchesSelector ||
228
            (function (s) {
229
                var matches = (_this.document || _this.ownerDocument).querySelectorAll(s), i = matches.length;
230
                while (--i >= 0 && matches.item(i) !== _this) { }
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
231
                return i > -1;
232
            });
233
}
234
235
var Polyfills = (function () {
236
    function Polyfills() {
237
    }
238
    Polyfills.elementMatches = polyfillElementMatches;
239
    Polyfills.mutationObserver = polyfillMutationObserver;
240
    return Polyfills;
241
}());
242
243
Polyfills.elementMatches();
244
Polyfills.mutationObserver();
245
Bindings.native();
246
Bindings.jQuery();
247
248
}(jQuery));
249